package StreamAPI;

import Lambda.dao.Employee;
import org.junit.Test;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 中间操作
 */
public class TestStreamApi2 {

    /**
     * 筛选与切片
     * filter——接收 Lambda ， 从流中排除某些元素。
     * limit——截断流，使其元素不超过给定数量。
     * skip(n) —— 跳过元素，返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个，则返回一个空流。与 limit(n) 互补
     * distinct——筛选，通过流所生成元素的 hashCode() 和 equals() 去除重复元素
     */
    List<Employee> employees = Arrays.asList(
            new Employee("张三", 18, 9999.99, Employee.Status.FREE),
            new Employee("李四", 38, 3333.99, Employee.Status.BUSY),
            new Employee("王五", 50, 6666.66, Employee.Status.BUSY),
            new Employee("赵六", 16, 3333.33, Employee.Status.FREE),
            new Employee("田七", 8, 7777.77, Employee.Status.BUSY),
            new Employee("田七", 8, 7777.77, Employee.Status.FREE),
            new Employee("田七", 8, 7777.77, Employee.Status.FREE)

    );

    public static Stream<Character> filterCharacter(String str) {
        List<Character> list = new ArrayList<>();
        for (Character ch : str.toCharArray()
        ) {
            list.add(ch);
        }
        return list.stream();
    }

    @Test
    public void testfilter() {
        //中间条件
        Stream<Employee> stream = employees.stream().filter((x) -> x.getAge() > 35);
        //终止操作
        stream.forEach(System.out::println);
    }

    @Test
    public void testlimit() {
        //中间操作
        Stream<Employee> stream = employees.stream().limit(10);
        //终止操作
        stream.forEach(System.out::println);
    }

    @Test
    public void testskip() {
        //中间操作
        Stream<Employee> stream = employees.stream().skip(2);
        //终止操作
        stream.forEach(System.out::println);
    }

    @Test
    public void testdistinct() {
        //中间操作
        Stream<Employee> stream = employees.stream().distinct();
        //终止操作
        stream.forEach(System.out::println);
    }

    //外部迭代
    @Test
    public void test2() {
        Iterator<Employee> it = employees.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }

    /*
		映射
		map——接收 Lambda ， 将元素转换成其他形式或提取信息。接收一个函数作为参数，该函数会被应用到每个元素上，并将其映射成一个新的元素。
		flatMap——接收一个函数作为参数，将流中的每个值都换成另一个流，然后把所有流连接成一个流
	 */
    @Test
    public void testmap() {
        //中间操作
        List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
        //终止操作
        list.stream().map((str) -> str.toUpperCase()).forEach(System.out::println);
        employees.stream().map(Employee::getName).distinct().forEach(System.out::println);
        Stream<Stream<Character>> streamStream = list.stream().map(TestStreamApi2::filterCharacter);
        streamStream.forEach((sm) -> sm.forEach(System.out::println));
    }

    @Test
    public void testflatMap() {
        //中间操作
        List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
        //终止操作
        list.stream().flatMap(TestStreamApi2::filterCharacter).forEach(System.out::println);

    }

    /**
     * sorted()——自然排序
     * sorted(Comparator com)——定制排序
     */
    @Test
    public void testsorted() {

        //中间操作
        List<String> list = Arrays.asList("fff", "aaa", "bbb", "ccc", "ddd", "eee");
        //终止操作
        list.stream().flatMap(TestStreamApi2::filterCharacter).sorted().forEach(System.out::println);

    }

    @Test
    public void testsorted2() {

        //中间操作
        List<String> list = Arrays.asList("fff", "aaa", "bbb", "ccc", "ddd", "eee");
        //终止操作
        employees.stream().sorted((e1, e2) -> {
                    if (e1.getAge().equals(e2.getAge())) {
                        return e1.getName().compareTo(e2.getName());
                    } else {
                        return e1.getAge().compareTo(e2.getAge());
                    }
                }
        ).forEach(System.out::println);

    }

    /**
     * 终止操作
     * 查找与匹配
     * allMatch(Predicate p) 检查是否匹配所有元素
     * anyMatch(Predicate p) 检查是否至少匹配一个元素
     * noneMatch(Predicate p) 检查是否没有匹配所有元素
     * findFirst() 返回第一个元素
     * findAny() 返回当前流中的任意元素
     * count() 返回流中元素总数
     * max(Comparator c) 返回流中最大值
     * min(Comparator c) 返回流中最小值
     * forEach(Consumer c) 内部迭代(使用 Collection 接口需要用户去做迭代，称为外部迭代。相反，Stream API 使用内部迭代——它帮你把迭代做了
     */
    @Test
    public void testallMatch() {
        boolean b = employees.stream().allMatch((X) -> X.getStatus().equals(Employee.Status.FREE));
        System.out.println(b);
    }

    @Test
    public void testanyMatch() {
        boolean b = employees.stream().anyMatch((X) -> X.getStatus().equals(Employee.Status.FREE));
        System.out.println(b);
    }

    @Test
    public void testnoneMatch() {
        boolean b = employees.stream().noneMatch((X) -> X.getStatus().equals(Employee.Status.FREE));
        System.out.println(b);
    }

    @Test
    public void testfindFirst() {
        Optional<Employee> first = employees.stream().sorted((x, y) -> Double.compare(x.getSalary(), y.getSalary())).findFirst();
        System.out.println(first.get());
    }

    @Test
    public void testfindAny() {
        Optional<Employee> any = employees.parallelStream().filter((x) -> x.getStatus().equals(Employee.Status.BUSY)).findAny();
    }

    @Test
    public void testcount() {
        long count = employees.parallelStream().filter((x) -> x.getStatus().equals(Employee.Status.BUSY)).count();
    }

    @Test
    public void testmax() {
        employees.parallelStream().filter((x) -> x.getStatus().equals(Employee.Status.BUSY)).max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
    }

    @Test
    public void testmin() {
        employees.stream().map(Employee::getSalary).min(Double::compare);
    }

    /**
     * 归约
     * reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来，得到一个值。 返回 T
     * <p>
     * reduce(BinaryOperator b) 可以将流中元素反复结合起来，得到一个值。 返回 Optional<T>
     */
    @Test
    public void testreduce() {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Integer sum = list.stream().reduce(0, (x, y) -> x + y);
        System.out.println(sum);
        Optional<Double> doublesum = employees.stream().map(Employee::getSalary).reduce(Double::sum);
        System.out.println(doublesum);
    }

    /**
     * 收集
     * <p>
     * collect(Collector c) 将流转换为其他形式。接收一个 Collector接口的
     * 实现，用于给Stream中元素做汇总的方法
     */
    @Test
    public void testcollect() {
        employees.stream().map(Employee::getName).collect(Collectors.toList()).forEach(System.out::println);
        System.out.println("-----------------------------------------------------------------------");
        employees.stream().map(Employee::getName).distinct().collect(Collectors.toSet()).forEach(System.out::println);
        System.out.println("-----------------------------------------------------------------------");
        employees.stream().map(Employee::getName).distinct().collect(Collectors.toCollection(HashSet::new)).forEach(System.out::println);

    }

    @Test
    public void testmaxcollect() {
        Optional<Double> max = employees.stream()
                .map(Employee::getSalary)
                .collect(Collectors.maxBy(Double::compare));

        System.out.println(max.get());
    }

    @Test
    public void testmincollect() {
        Optional<Employee> op = employees.stream()
                .collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));

        System.out.println(op.get());
    }

    @Test
    public void testsummingcollect() {
        Double sum = employees.stream()
                .collect(Collectors.summingDouble(Employee::getSalary));

        System.out.println(sum);
    }

    @Test
    public void testaveragingcollect() {
        Double avg = employees.stream()
                .collect(Collectors.averagingDouble(Employee::getSalary));

        System.out.println(avg);
    }

    @Test
    public void testcountcollect() {
        Long count = employees.stream()
                .collect(Collectors.counting());
        System.out.println(count);
    }

    @Test
    public void testummarizingcollect() {
        DoubleSummaryStatistics dss = employees.stream().collect(Collectors.summarizingDouble(Employee::getSalary));

        System.out.println(dss.getMax());
    }

    //分组
    @Test
    public void groupingBycollect() {
        Map<Employee.Status, List<Employee>> map = employees.stream()
                .collect(Collectors.groupingBy(Employee::getStatus));

        System.out.println(map);
    }

    //多级分组
    @Test
    public void groupingByCollectors() {
        Map<Employee.Status, Map<String, List<Employee>>> map = employees.stream()
                .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
                    if (e.getAge() >= 60)
                        return "老年";
                    else if (e.getAge() >= 35)
                        return "中年";
                    else
                        return "成年";
                })));

        System.out.println(map);
    }

    //分区
    @Test
    public void testpartitioningBy() {
        Map<Boolean, List<Employee>> map = employees.stream()
                .collect(Collectors.partitioningBy((e) -> e.getSalary() >= 5000));

        System.out.println(map);
    }

    //
    @Test
    public void testjoiningcollect() {
        String str = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.joining(",", "----", "----"));

        System.out.println(str);
    }

    @Test
    public void testreducing() {
        Optional<Double> sum = employees.stream()
                .map(Employee::getSalary)
                .collect(Collectors.reducing(Double::sum));

        System.out.println(sum.get());
    }
}
